// File: jmcomic-core/src/main/java/dev/jukomu/common/base/cli/InputListenerThread.java
package dev.jukomu.common.base.cli;

import dev.jukomu.common.base.concurrent.StopFlag;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 对应Python的InputListenerThread，用于在后台监听控制台输入。
 */
public class InputListenerThread extends Thread {

    private final String message; // 提示信息
    private final AtomicReference<String> userInput = new AtomicReference<>(null); // 原子引用，用于线程安全地存储用户输入

    /**
     * 构造函数。
     *
     * @param msg 打印给用户的提示信息。
     */
    public InputListenerThread(String msg) {
        this.message = msg;
        this.setDaemon(true); // 设置为守护线程，主线程退出时它也会退出
    }

    @Override
    public void run() {
        try {
            System.out.println(message);
            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
            String line = reader.readLine(); // 阻塞等待用户输入
            if (line != null) {
                userInput.set(line);
            }
        } catch (java.io.IOException e) {
            // IO异常，通常表示输入流已关闭
        } catch (Exception e) {
            // 其他异常
            System.err.println("Input listener thread encountered an error: " + e.getMessage());
        }
    }

    /**
     * 获取用户输入。
     *
     * @param timeoutMillis 等待超时时间（毫秒）。
     * @return 如果在超时时间内有输入，则返回输入字符串；否则返回null。
     * @throws InterruptedException 如果等待被中断。
     */
    public String getInput(long timeoutMillis) throws InterruptedException {
        this.join(timeoutMillis); // 等待指定时间
        return userInput.get(); // 返回当前获取到的输入
    }

    /**
     * 阻塞等待用户输入，并在等待期间定期检查停止标志。
     *
     * @param exitMsg        强制退出时显示的消息。
     * @param timeoutSeconds 初始等待超时时间（秒）。
     * @param flag           停止标志（可选）。
     * @return 用户输入的字符串。
     * @throws InterruptedException 如果收到停止信号或线程异常退出。
     */
    public String joinWaitInput(String exitMsg, double timeoutSeconds, StopFlag flag) throws InterruptedException {
        this.start(); // 启动监听线程
        long timeoutMillis = (long) (timeoutSeconds * 1000);

        // 使用一个特殊的哨兵对象来区分“没有输入”和“线程已结束但没有有效输入”
        final Object SENTINEL = new Object();
        AtomicReference<Object> result = new AtomicReference<>(SENTINEL);

        while (true) {
            // 如果收到停止信号
            if (flag != null && flag.shouldStop()) {
                throw new InterruptedException(exitMsg);
            }

            // 等待一段时间
            this.join(timeoutMillis);

            String input = userInput.get();
            if (input != null) {
                // 已收到用户输入
                return input;
            }

            // 如果线程已经结束但没有输入，说明发生了异常或输入流关闭
            if (!this.isAlive()) {
                throw new InterruptedException(exitMsg);
            }

            // 超时但没有输入，打印提示信息并增加下次等待时间
            System.out.println(message);
            timeoutMillis = (long) (timeoutMillis * 1.5);
        }
    }
}